package com.visikard.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;

import com.visikard.ui.R;
import com.visikard.utility.BitmapUtils;

public class PuchRatingBar extends View {
	private final static int QUAD_HALF_CIRCLE = 90;
	Paint mTextPaint = null;
	Bitmap mActiveStar;
	Bitmap mNormalStar;
	Bitmap mAnimationStar;

	private float mWidth;
	private float mHeight;
	private int mMaxLines = 1;
	private int mMaxStars = 5;
	private int mMaxStarsPerLine;
	private int currentRating = 0;
	private Context mContext;

	private float mStarX;
	private float mStarY;
	private boolean mIsAnimation = false;
	private int mFramePerSecond = 24; // to calculate time to redraw animation star
	private int mAngle; // use for rotate animation
	private int mAngleStep;

	private Point mP0, mP1, mP2; // use for bzier curves

	public PuchRatingBar(Context context) {
		super(context);
		mContext = context;
		initilize();
	}

	public PuchRatingBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		initilize();
	}

	public PuchRatingBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mContext = context;
		initilize();
	}

	private void initilize() {
		mTextPaint = new Paint();
		mTextPaint.setDither(true);
		mTextPaint.setAntiAlias(true);
		mTextPaint.setFilterBitmap(true);
		mNormalStar = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.wallet_star_medium);
		mActiveStar = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.wallet_star_medium_act);
		mAnimationStar = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.wallet_star_animation);
	}

	public void setMaxLines(int lines) {
		mMaxLines = lines;
	}

	public void setRating(int rate, int total) {
		if (total > 0 && rate <= total) {
			mMaxStars = total;
			currentRating = rate;
		}
	}

	public int getRating() {
		return currentRating;
	}

	public int getMaxRating() {
		return mMaxStars;
	}

	public void setAnimation(boolean isAnimation) {
		mIsAnimation = isAnimation;
		mAngleStep = QUAD_HALF_CIRCLE / mFramePerSecond;
		mAngle = -mAngleStep;
		mStarX = mWidth / mMaxStarsPerLine * ((currentRating - 1) % mMaxStarsPerLine + 0.5f);
		mStarY = mHeight / mMaxLines * ((currentRating - 1) / mMaxStarsPerLine + 0.5f);
		mP0 = new Point((int) mStarX, (int) (mStarY + mWidth / 2));
		mP1 = new Point((int) (mStarX - mWidth / 8), (int) (mStarY + mWidth / 4));
		mP2 = new Point((int) mStarX, (int) mStarY);
		requestLayout();
		invalidate();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) {
			mWidth = MeasureSpec.getSize(widthMeasureSpec);
			float mStarRectEdge;
			mMaxStarsPerLine = (mMaxStars % mMaxLines > 0 && mMaxLines > 1) ? mMaxStars / mMaxLines + 1 : mMaxStars
					/ mMaxLines;
			mHeight = mContext.getResources().getDimension(R.dimen.top_menu_bar_height) * mMaxLines;
			if (mWidth / mMaxStarsPerLine > mContext.getResources().getDimension(R.dimen.top_menu_bar_height))
				mStarRectEdge = mContext.getResources().getDimension(R.dimen.top_menu_bar_height);
			else
				mStarRectEdge = mWidth / mMaxStarsPerLine;
			mActiveStar = BitmapUtils
					.scaleCenterCrop(mTextPaint, mActiveStar, (int) mStarRectEdge, (int) mStarRectEdge);
			mNormalStar = BitmapUtils
					.scaleCenterCrop(mTextPaint, mNormalStar, (int) mStarRectEdge, (int) mStarRectEdge);
			setMeasuredDimension((int) mWidth, (int) mHeight);
		}
		if (mIsAnimation)
			setMeasuredDimension((int) mWidth, (int) mWidth);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		drawStarRank(canvas, mIsAnimation);
	}

	private void drawStarRank(Canvas canvas, boolean isAnimation) {
		for (int i = 0; i < mMaxStars; i++) {
			float canvasStartX = mWidth / mMaxStarsPerLine * (i % mMaxStarsPerLine + 0.5f) - mActiveStar.getWidth() / 2;
			float canvasStartY = mHeight / mMaxLines * (i / mMaxStarsPerLine + 0.5f) - mActiveStar.getHeight() / 2;
			if (i < currentRating - 1 || (i == currentRating - 1 && !isAnimation))
				canvas.drawBitmap(mActiveStar, canvasStartX, canvasStartY, mTextPaint);
			else if (i == currentRating - 1 && isAnimation) {
				if (mAngle < QUAD_HALF_CIRCLE) {
					mAngle += mAngleStep;
					Point bezierPoint = calculateBezierPoint((float) mAngle / QUAD_HALF_CIRCLE, mP0, mP1, mP2);
					canvas.save();
					canvas.rotate(mAngle, bezierPoint.x, bezierPoint.y);
					mAnimationStar = BitmapUtils.scaleCenterCrop(mTextPaint, mAnimationStar,
							(int) (mActiveStar.getHeight() * (2 - (float) mAngle / QUAD_HALF_CIRCLE)),
							(int) (mActiveStar.getWidth() * (2 - (float) mAngle / QUAD_HALF_CIRCLE)));
					TextPaint textPaint = new TextPaint(mTextPaint);
					textPaint.setAlpha(mAngle * 255 / QUAD_HALF_CIRCLE);
					canvas.drawBitmap(mAnimationStar, bezierPoint.x - mAnimationStar.getWidth() / 2, bezierPoint.y
							- mAnimationStar.getHeight() / 2, textPaint);
					canvas.restore();
					postInvalidateDelayed(250 / mFramePerSecond);
				}
				else
					canvas.drawBitmap(mActiveStar, mStarX - mActiveStar.getWidth() / 2,
							mStarY - mActiveStar.getHeight() / 2, mTextPaint);
			}
			else
				canvas.drawBitmap(mNormalStar, canvasStartX, canvasStartY, mTextPaint);
		}
	}

	Point calculateBezierPoint(float t, Point p0, Point p1, Point p2) {
		float u = 1 - t;
		float uu = u * u;
		float tt = t * t;
		Point p = new Point((int) (p0.x * uu), (int) (p0.y * uu));
		p.set((int) (p.x + 2 * u * t * p1.x), (int) (p.y + 2 * u * t * p1.y));
		p.set((int) (p.x + tt * p2.x), (int) (p.y + tt * p2.y));
		return p;
	}
}
